package com.hqd.jjvm.classformat.attributeinfo;

import com.hqd.jjvm.classformat.ClassFile;
import com.hqd.jjvm.classformat.InstructionCode;
import com.hqd.jjvm.util.HexStrTransformUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

@Getter
public class Code extends AttributeInfo {
    /**
     * 最大栈深度
     */
    private Integer maxStack;
    /**
     * 局部变量表大小
     */
    private Integer maxLocals;
    /**
     * 字节码长度
     */
    private Integer codeLength;
    private InstructionCode instructionCode;
    private Integer exceptionLength;
    private List<ExceptionTable> exceptionTables;
    private Integer attributesCount;
    private List<AttributeInfo> attributeInfos;

    private ExceptionTable parseExceptionTable(ClassFile classFile) {
        int startPc = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        int endPc = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        int handlerPc = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        int catchType = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        return new ExceptionTable(startPc, endPc, handlerPc, catchType);
    }

    @Override
    protected AttributeInfo newAttributeInfo(Integer attributeNameIndex, Integer attributeLength, ClassFile classFile) {
        this.maxStack = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        this.maxLocals = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        this.codeLength = HexStrTransformUtil.parseHexToInt(classFile.readU4());
        this.instructionCode = new InstructionCode(classFile.read(codeLength));
        this.exceptionLength = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        this.exceptionTables = new ArrayList<>(exceptionLength);
        for (int i = 0; i < exceptionLength; i++) {
            exceptionTables.add(parseExceptionTable(classFile));
        }
        this.attributesCount = HexStrTransformUtil.parseHexToInt(classFile.readU2());
        List<AttributeInfo> attributeInfos = classFile.parseAttributeInfo(attributesCount);
        this.attributeInfos = attributeInfos;
        return this;
    }

    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public class ExceptionTable {
        private Integer startPc;
        private Integer endPc;
        private Integer handlerPc;
        private Integer catchTypeIndex;
    }
}
